#include "rclcpp/rclcpp.hpp"
// 导入接口类型
#include "std_msgs/msg/string.hpp"
#include "std_msgs/msg/u_int32.hpp"
//导入服务接口
#include "bot_interface/srv/test.hpp" //购买接口
#include "bot_interface/srv/identify.hpp"//借钱接口

#include <queue>

//使用OOP
/*
    创建一个类节点，名字叫做SingleDogNode,继承自Node.
*/
class SingleDogNode : public rclcpp::Node
{
public:
    // 构造函数,有一个参数为节点名称
    SingleDogNode(std::string name) : Node(name)
    {
        // 打印一句自我介绍
        RCLCPP_INFO(this->get_logger(), "hello world,I'm bot_cpp_OOP node.%s.",name.c_str());
        //creat subscripition to subscribe the topic  by "subscribe something"

        //创建订阅者，需要传入 话题类型 话题名称 所需要绑定的callback 通信Qos

        //这里订阅了 类型 std_msgs::msg::String  名字"Topic_test"的话题。
        //对应`node_py_test/node_py_test/lisi.py`-->self.create_publisher(String,"Topic_test",10)
        sub_novel = this->create_subscription<std_msgs::msg::String>
        ("Topic_test",10,
        std::bind(&SingleDogNode::callBackReceviedTopicData,
        this,std::placeholders::_1));

        //创建发布者
        //create topic_type:std_msgs::msg::Uint32 topic_name:"uint32_topic_test" Qos:10
        pub_money=this->create_publisher<std_msgs::msg::UInt32>("uint32_topic_test",10);
        //========================================================================================================
        //========================================================================================================
        //instance callback group
        callback_group_service_=this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);

        // 创建服务端
        // std::bind 将成员函数 包装成回调
        // rmw_qos_profile_services_default
        sell_server=this->create_service<bot_interface::srv::Test>("sell_novel",
        std::bind(&SingleDogNode::serviceTestCallBack,this,std::placeholders::_1,std::placeholders::_2),
        rmw_qos_profile_services_default,
        callback_group_service_);

        // param setting
        this->declare_parameter<std::int64_t>("book_price",book_price);
    }

private:
    // declare subscriber 声明一个订阅者
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_novel;

    // declare publisher to send data to subscriber
    rclcpp::Publisher<std_msgs::msg::UInt32>::SharedPtr pub_money;

    rclcpp::TimerBase::SharedPtr timer;

    std::queue <std::string> book_queue;

    // declare book price
    unsigned int book_price = 1;

    //声明服务端
    rclcpp::Service<bot_interface::srv::Test>::SharedPtr sell_server;

    //在每次收到服务请求后，单独开一个线程处理
    //ROS2中使用多线程执行器和回调组来实现多线程
    //callback group
    rclcpp::CallbackGroup::SharedPtr callback_group_service_;


    //收到话题数据时的callback
    void callBackReceviedTopicData(const std_msgs::msg::String::SharedPtr msg)
    {
        std_msgs::msg::UInt32 money;
        money.data=10;
        //收到数据回复前，先发送参数给另一方
        pub_money->publish(money);
        book_queue.push(msg->data);
        RCLCPP_INFO(this->get_logger(),"recevied  '%s' the service and send '%d'",msg->data.c_str(),money.data);
    }

    //调用服务时的回调
    void serviceTestCallBack(const bot_interface::srv::Test::Request::SharedPtr request,
    const bot_interface::srv::Test::Response::SharedPtr response)
    {
        RCLCPP_INFO(this->get_logger(),"hello,recevied 'sell novel' request and privide %d .",request->nums);
        
        // call this  service mean that someone want to  buy a book. We update the book_price param
        // update menber value `book_price`
        this->get_parameter("book_price",book_price);

        // recalculate number of book
        unsigned int book_num = (int)request->nums/(book_price);
        if (book_num>book_queue.size())
        {
            //timer 
            rclcpp::Rate rate(1);
            RCLCPP_INFO(this->get_logger(),"Ooops. Queue size: %d , real need %d .",book_queue.size(),book_num);
            while (book_queue.size()<book_num)
            {
                RCLCPP_INFO(this->get_logger(),"Waitting. Need more %d .",book_num-book_queue.size());
                // sleep 1s
                rate.sleep();
            }
            
        }
        RCLCPP_INFO(this->get_logger(),"Nice. Queue size: %d , real need %d .",book_queue.size(),book_num);
        for(size_t i=0;i<book_num;++i)
        {
            response->str_array.push_back(book_queue.front());
            book_queue.pop();
        }
    }
};

//主函数中首先初始化rclcpp，然后新建了一个Node节点的对象，命名为bot，
//接着使用rclcpp让这个节点暴露在外面，并检测退出信号（Ctrl+C），
//检测到退出信号后，就会执行rcl.shutdown()关闭节点。

// int main(int argc, char **argv)
// {
//     rclcpp::init(argc, argv);
//     /*产生一个bot的节点*/
//     auto node = std::make_shared<rclcpp::Node>("bot");
//     // 打印一句自我介绍
//     RCLCPP_INFO(node->get_logger(), "hello world,I'm bot node.");
//     /* 运行节点，并检测退出信号*/
//     rclcpp::spin(node);
//     rclcpp::shutdown();
//     return 0;
// }



int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    /*产生一个bot的节点*/
    auto node = std::make_shared<SingleDogNode>("bot");

    //creat multi-threading executors
    rclcpp::executors::MultiThreadedExecutor executors;
    //add node to the executors
    executors.add_node(node);
    executors.spin();

    /* 运行节点，并检测退出信号*/

    // when using multi-threading executors,delete it's spin interface
    //rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}